<template>
  <!-- 
    跨组件通信,相关数据放在pinia中
   -->
   <!-- 
    isShow默认是true,此时展示属性列表
    isShow变为false,展示的是新增或者修改功能的视图
        在这个视图中,应禁用属性列表视图中的三级列表
    -->
  <Category :disabled="!isShow"/>

  <el-card shadow="always" :body-style="{ padding: '20px' }" v-if="isShow">
    <template #header>
      <el-button
        type="primary"
        size="default"
        @click="isShow = false"
        :icon="Plus"
      >
        新增属性
      </el-button>
    </template>
    <!-- card body -->
    <el-table border stripe :data="attrList">
      <el-table-column label="序号" type="index" width="80" />
      <el-table-column label="属性名称" width="150" prop="attrName">
      </el-table-column>

      <el-table-column label="属性值名称列表" prop="attrValueList">
        <!-- 遍历属性值列表,etag展示 -->
        <template #default="{ row }">
          <el-tag
            type="danger"
            size="default"
            effect="dark"
            v-for="item in row.attrValueList"
            :key="item.id"
            :style="{ marginRight: '10px' }"
          >
            {{ item.valueName }}
          </el-tag>
        </template>
      </el-table-column>

      <el-table-column label="操作" width="150">
        <template v-slot="{ row }">
          <el-button
            type="warning"
            size="default"
            @click="changeAttr(row)"
            :icon="Edit"
          ></el-button>
          <el-popconfirm
            title="你确定要删除这个属性吗???"
            @confirm="deleteAttr(row.id)"
          >
            <template #reference>
              <el-button
                type="danger"
                size="default"
                :icon="Delete"
              ></el-button>
            </template>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>
  </el-card>

  <el-card shadow="always" :body-style="{ padding: '20px' }" v-else>
    <template #header>
      <el-form label-width="80px" :inline="true">
        <el-form-item label="属性名">
          <!-- v-model双向数据绑定收集新增内容 -->
          <el-input v-model="attrForm.attrName"></el-input>
        </el-form-item>
      </el-form>

      <div>
        <!-- 如果新增属性页的属性名不存在,禁用新增属性值按钮 -->
        <el-button 
        type="primary" 
        @click="addAttrValue"
        :disabled="!attrForm.attrName"
        >添加属性值</el-button>
        <el-button type="default" @click="isShow = true">取消</el-button>
      </div>
      <!-- 
        为什么attrForm.attrValueList

       -->
      <el-table border stripe :data="attrForm.attrValueList">
        <el-table-column label="序号" type="index" width="80" align="center" />
        <el-table-column label="属性值名称" align="center" prop="valueName">
          <template v-slot="{ row, $index }">
            <el-input
              v-model="row.valueName"
              placeholder="请输入新增的属性值名称"
              size="default"
              v-if="row.isEdit"
              ref="editEle"
              @blur="changeTolook(row, $index)"
              @focus="saveOldValue(row)"
            ></el-input>
            <!-- 
              查看和编辑的状态通过input和span两个结构实现
              -点击新增属性时,就是编辑状态
              -点击编辑按钮时
               -默认是查看状态
               -当点击某一个属性值时,有查看状态变成编辑状态
             -->
            <span v-else @click="changeToEdit(row)">{{ row.valueName }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center">
          <template #default="{ $index }">
            <el-button
              type="danger"
              size="default"
              @click="deleteAttrValue($index)"
              icon="ele-Delete"
            ></el-button>
          </template>
        </el-table-column>
      </el-table>
      <div style="margin-top: 30px">
        <el-button type="primary" @click="saveAttr" :disabled="attrForm.attrValueList.length <= 0 || !attrForm.attrName">保存</el-button>
        <el-button type="default" @click="isShow = true">取消</el-button>
      </div>
    </template>
    <!-- card body -->
  </el-card>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "Attr",
});
</script>

<script setup lang="ts">
import { Plus, Edit, Delete } from "@element-plus/icons-vue";
import useAttrListStore from "@/stores/attr";
import { storeToRefs } from "pinia";
import { watch, ref, nextTick } from "vue";
import {
  requestAttrList,
  requestDeleteAttr,
  requestUpdateOrAddAttr,
} from "@/api/attr";
import type { attrListType, attrType, attrValueItemType } from "@/api/attr";
import { ElMessage } from "element-plus";

//1,获取三级分类列表的逻辑
//解构store中的数据
const attrStore = useAttrListStore();
const { category1Id, category2Id, category3Id } = storeToRefs(attrStore);

//初始化三级列表响应式数据
const attrList = ref<attrListType>([]);

//封装获取属性列表的请求函数
const getAttrList = async () => {
  const result = await requestAttrList(
    category1Id.value as number,
    category2Id.value as number,
    category3Id.value as number
  );
  attrList.value = result;
};

//监听category3的变化,一旦3类选项有值或者值发生变化就应该立刻发生请求
watch(
  category3Id,
  (newValue) => {
    //如果三级列表项变成了null,需要把现有的数据清空
    if (!newValue) {
      attrList.value = [];
      return;
    }
    //发起属性列表请求
    getAttrList();
  },
  { immediate: true }
);

//2,新增属性的逻辑

//控制显示与隐藏
const isShow = ref(true);

//初始化添加的数据
//双向数据绑定收集新数据
const attrForm = ref<attrType>({
  attrName: "",
  categoryId: category3Id.value as number,
  categoryLevel: 3, //默认只添加第三级列表的属性
  attrValueList: [],
});
//当用户点击添加属性值时,向初始数据中增加一行,
//同时在属性值中增加input结构,以便用户填写具体的值
const addAttrValue = () => {
  const newAttrValue = ref({
    valueName: "",
    attrId: attrForm.value.id, //此id后台不会自动生成.需手动添加
    //新增一个控制编辑状态和可读状态的逻辑数据
    isEdit: true,
  });
  //把新增的属性值数据添加到属性列表中
  attrForm.value.attrValueList.push(newAttrValue.value);

  //新增默认是编辑状态,默认输入框是获取焦点的
  nextTick(() => {
    editEle.value.focus();
  });
};

// 3,修改属性的逻辑
const changeAttr = (row: attrType) => {
  isShow.value = false;
  //遍历row中所有的属性值,
  row.attrValueList.forEach((item) => {
    //进入编辑模式,默认是只读
    item.isEdit = false;
  });
  //渲染页面的数据都是基于attrForm的动态数据
  attrForm.value = row;
};

//点击编辑页面的某一个属性,状态有查看变成编辑
const editEle = ref();
const changeToEdit = (row: attrValueItemType) => {
  row.isEdit = true;
  //编辑状态下的输入框是默认获取焦点状态
  //涉及到d操作真实dom,需等真实dom渲染完成之后再操作
  nextTick(() => {
    editEle.value.focus();
  });
};

//在失焦之前,可以在获取焦点时保存原有的数据
let oldAttrValueName = "";
const saveOldValue = (row: attrValueItemType) => {
  oldAttrValueName = row.valueName;
  // console.log(oldAttrValueName,"属性值的原有值");
};

//当编辑状态的表单失去焦点函数
const changeTolook = (row: attrValueItemType, $index: number) => {
  //1,由编辑状态变为查看状态,
  //   属性值对象中的isEdit属性是控制编辑和查看状态切换的数据
  row.isEdit = false;
  /* 
  2,新增表单时,未填写任何内容,就使输入框失去焦点
   修改表单时,将所有内容清空,为重新输入内核内容,就使输入框失去焦点
  3,由此需要判断是修改还是新增
    如果是修改 => 则表单有初始值
       => 希望在清空了数据但没有新设任何数据的情况下失去焦点时
       => 将原有的值填入输入框
    如果是新增 => 则表单没有初始值 => 删除这个无效的新属性
  */
  //判断失去焦点时,输入框是否有内容
  if (!row.valueName.trim()) {
    //如果是更新的输入框为空,删除这条无效信息
    if (!oldAttrValueName) {
      attrForm.value.attrValueList.splice($index, 1);
    } else {
      //如果是修改操作,把初始值重新设置回去
      row.valueName = oldAttrValueName;
    }
  }

  //去除修改和新增重复项
  let isRepeat = attrForm.value.attrValueList.some((item) => {
    //排己比较法
    /* 
      attrValueList中的每一项数据和row中的每一项数据的来源相同
      如果不排己,送么函数的返回值永远是true
      无法筛选出重复项
    */
    if (item === row) {
      return;
    }
    //除了自己之外,只要有意向满足就存在重复项
    //因为此项目中的数据一次只能改一条,所以此方法可行
    //如果一次可修改多条数据,可能需要使用filter
    return item.valueName === row.valueName;
  });

  //如果isRepeat为true,则存在重复,
  if (isRepeat) {
    //如果是修改后的值与其他值冲突,则将修改后的值改为原值
    if (oldAttrValueName) {
      row.valueName = oldAttrValueName;
    } else {
      //如果是新增的重复数据,直接删除该条新增数据
      attrForm.value.attrValueList.splice($index, 1);
    }
    //同一清空旧值
    oldAttrValueName = "";
  }
};

//删除单个属性值
const deleteAttrValue = ($index: number) => {
  attrForm.value.attrValueList.splice($index, 1);
};

//点击保存按钮,发送新增或者更新的请求
const saveAttr = async () => {
  //请求参数newAttrValue中新增了控制查看和编辑的逻辑参数
  //1,删除多余的请求参数
  attrForm.value.attrValueList.forEach((item) => {
    delete item.isEdit;
  });

  //判断当前的属性值列表是否为空,如果为空就不提交了
  if (attrForm.value.attrValueList.length <= 0) {
    ElMessage.error("属性值列表不能为空");
    return;
  }

  //如果属性值列表有值,,判断是更新的新值还是修改的值
  //如果是修改的值 => 需要判断是否有值更新 => 若有就发送请求,没有就直接返回上一页

  //发送请求
  try {
    await requestUpdateOrAddAttr(attrForm.value);
    ElMessage.success("新增或修改成功");
    //返回上一页
    isShow.value = true;
    getAttrList();
  } catch (e) {
    ElMessage.error("新增或修改失败");
  }
};

//删除某个属性
const deleteAttr = async (id: number) => {
  try {
    await requestDeleteAttr(id);
    //重新发送请求
    getAttrList();
  } catch (error) {
    ElMessage.error("删除属性失败");
  }
};
</script>
